<script lang="ts" setup>
import { ref, watch } from 'vue'
import MarkdownIt from 'markdown-it'
import hljs from 'highlight.js'
// 基于 Atom 编辑器的亮色主题，色彩鲜艳且对比明显
import 'highlight.js/styles/atom-one-light.css'

const props = defineProps({
	msg: {
		type: String,
		required: true,
		default: '',
	},
})

const renderedMarkdown = ref('')
// 创建 markdown-it 实例，并配置代码高亮
const md = new MarkdownIt({
	html: true,
	linkify: true,
	typographer: true,
	highlight: (str: string, lang: string) => {
		const linesLength = str.split(/\n/).length - 1
		// 生成行号
		let linesNum = '<span aria-hidden="true" class="line-numbers-rows">'
		for (let index = 0; index < linesLength; index++) {
			linesNum = linesNum + '<span></span>'
		}
		linesNum += '</span>'

		// 生成代码高亮
		if (lang && hljs.getLanguage(lang)) {
			try {
				return `<pre class="md-pre"><code>${
					hljs.highlight(str, { language: lang, ignoreIllegals: true }).value
				}</code>${linesNum}</pre>`
			} catch (__) {
				console.log(__, 'error')
			}
		}
		return `<p>${md.utils.escapeHtml(str)}${linesNum}</p>`
	}
})

// 修改渲染规则以添加复制按钮
md.renderer.rules.fence = (tokens, idx, options, env, slf) => {
	const token = tokens[idx]
	const code = token.content
	const lang = token.info
	const highlightedCode = md.options.highlight(code, lang)
	const codeId = `code-${idx}`
	// 添加语言
	return `
		<div class="code-container" id="${codeId}">
			<div class="code-header">
				<span class="code-lang">${lang || 'plaintext'}</span>
			</div>
			<div class="code-view">
				${highlightedCode}
			</div>
		</div>
    `
}

watch(
	() => props.msg,
	(msg) => {
		if (!msg) {
			return
		}
		renderedMarkdown.value = md.render(msg)
	},
	{
		immediate: true,
	}
)
</script>
<template>
	<div class="markdown-com">
		<div v-html="renderedMarkdown"></div>
	</div>
</template>
<style lang="scss">
.markdown-com {
	color: #333;
	font-size: 16px;
	line-height: 1.6;
	* {
		transition: none !important; /* 禁用过渡效果 */
	}
	strong {
		font-weight: 600;
		font-size: 16px;
	}
	h1,
	h2,
	h3,
	h4,
	h5,
	h6 {
		margin-top: 24px;
		margin-bottom: 16px;
		font-weight: 600;
		line-height: 1.25;
	}
	hr {
		height: 0;
		width: 0;
		margin: 0;
	}
	blockquote,
	dl,
	ol,
	p,
	pre,
	table,
	ul {
		margin-bottom: 16px;
	}
	ul,
	ol {
		// padding-left: 20px;
		li > p {
			margin-top: 16px;
		}
	}
	pre {
		p,
		code {
			white-space: pre-wrap;
			line-height: 1.4;
			color: #000;
		}
		&.md-pre {
			background: #e6e7e9;
			transition: background 0.1s ease-in-out;
			position: relative;
			padding: 6px;
			padding-left: 30px;
			margin: 10px 0;
			border-radius: 4px;
			code {
				text-align: left;
				// white-space: pre-wrap;
				line-height: 1.6;
			}

			// 行号
			/*
				参考文档：
					https://juejin.cn/post/6844904105970761741?searchId=20250311140701E2B426468B52A24C738B
				*/
			.line-numbers-rows {
				position: absolute;
				pointer-events: none;
				top: 6px;
				bottom: 6px;
				left: 0;
				font-size: 100%;
				width: 30px;
				text-align: center;
				letter-spacing: -1px;
				// border-right: 1px solid rgba(0, 0, 0, 0.66);
				user-select: none;
				counter-reset: linenumber;
				line-height: 1.6;
				span {
					pointer-events: none;
					display: block;
					counter-increment: linenumber;
					&:before {
						content: counter(linenumber);
						display: block;
						text-align: center;
						color: #b3b3b3;
						transition: color 0.1s ease-in-out;
					}
				}
			}
		}
	}
	.code-container {
		.code-header {
			display: flex;
			justify-content: flex-start;
			align-items: center;
			height: 40px;
			background: #e6e7e9;
			margin-bottom: -12px;
			padding: 0 20px;
			.code-lang {
				margin-right: 10px;
			}
			button {
				margin: 0 10px;
				display: none;
			}
		}
	}
	.think{
		border-left: 2px solid #e5e5e5;
		padding-left: 10px;
		color: #8b8b8b;
	}
}
</style>
